﻿/*
 * User: RSny
 * Date: 5/8/2012
 * Time: 12:37 PM
 */
using System;
using System.Runtime.InteropServices;

namespace Aspects.PInvoke
{
    public partial class Native
    {
        #region Structures

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct BLUETOOTH_DEVICE_INFO
        {
            public UInt32 dwSize;
            public UInt64 Address;
            public uint ulClassofDevice;
            public bool fConnected; //Specifies whether the device is connected.
            public bool fRemembered;
            public bool fAuthenticated;
            public SYSTEMTIME stLastSeen;
            public SYSTEMTIME stLastUsed;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 248)]
            public string szName;

            public void Initialize()
            {
                this.dwSize = (uint)Marshal.SizeOf(typeof(BLUETOOTH_DEVICE_INFO));
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SYSTEMTIME
        {
            [MarshalAs(UnmanagedType.U2)]
            public short Year;
            [MarshalAs(UnmanagedType.U2)]
            public short Month;
            [MarshalAs(UnmanagedType.U2)]
            public short DayOfWeek;
            [MarshalAs(UnmanagedType.U2)]
            public short Day;
            [MarshalAs(UnmanagedType.U2)]
            public short Hour;
            [MarshalAs(UnmanagedType.U2)]
            public short Minute;
            [MarshalAs(UnmanagedType.U2)]
            public short Second;
            [MarshalAs(UnmanagedType.U2)]
            public short Milliseconds;

            public SYSTEMTIME(DateTime dt)
            {
                dt = dt.ToUniversalTime();  // SetSystemTime expects the SYSTEMTIME in UTC
                Year = (short)dt.Year;
                Month = (short)dt.Month;
                DayOfWeek = (short)dt.DayOfWeek;
                Day = (short)dt.Day;
                Hour = (short)dt.Hour;
                Minute = (short)dt.Minute;
                Second = (short)dt.Second;
                Milliseconds = (short)dt.Millisecond;
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct BLUETOOTH_DEVICE_SEARCH_PARAMS
        {
            internal UInt32 dwSize;
            internal bool fReturnAuthenticated; //return authenticated Bluetooth devices.
            internal bool fReturnRemembered; //return remembered Bluetooth devices
            internal bool fReturnUnknown; // return unknown Bluetooth devices
            internal bool fReturnConnected; //return connected Bluetooth devices
            internal bool fIssueInquiry; //new inquiry should be issued.
            internal byte cTimeoutMultiplier;//time out for the inquiry, expressed in increments of 1.28 seconds. 
            internal IntPtr hRadio; //radio on which to perform the inquiry

            internal void Initialize()
            {
                this.dwSize = (uint)Marshal.SizeOf(typeof(BLUETOOTH_DEVICE_SEARCH_PARAMS));
            }
        }

        /// <summary>
         /// The BLUETOOTH_FIND_RADIO_PARAMS structure facilitates enumerating installed Bluetooth radios.
         /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct BLUETOOTH_FIND_RADIO_PARAM
         {
             internal UInt32 dwSize;
             internal void Initialize()
             {
                 this.dwSize = (UInt32)Marshal.SizeOf(typeof(BLUETOOTH_FIND_RADIO_PARAM));
             }
         }

        public const int BLUETOOTH_MAX_NAME_SIZE = 248;

        /// <summary>
         /// The BLUETOOTH_RADIO_INFO structure contains information about a Bluetooth radio.
         /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct BLUETOOTH_RADIO_INFO
         {
             internal UInt32 dwSize;
             internal UInt64 address;
             [MarshalAs(UnmanagedType.ByValTStr, SizeConst = BLUETOOTH_MAX_NAME_SIZE)]
             internal string szName;
             internal UInt32 ulClassOfDevice;
             internal UInt16 lmpSubversion;
             internal UInt16 manufacturer;

             internal void Initialize()
             {
                 this.dwSize = (UInt32)Marshal.SizeOf(typeof(BLUETOOTH_RADIO_INFO));
             }
         }

        #endregion

        #region Enumerators

        public enum BLUETOOTH_AUTHENTICATION_REQUIREMENTS
        {
            MITMProtectionNotRequired                 = 0x00,
            MITMProtectionRequired                    = 0x01,
            MITMProtectionNotRequiredBonding          = 0x02,
            MITMProtectionRequiredBonding             = 0x03,
            MITMProtectionNotRequiredGeneralBonding   = 0x04,
            MITMProtectionRequiredGeneralBonding      = 0x05,
            MITMProtectionNotDefined                  = 0xff 
        }

        public enum ERROR_CODES : uint
        {
            SUCCESS = 0,
            ERROR_CANCELLED = 1, //The user canceled the operation.
            ERROR_INVALID_PARAMETER = 87, //The device structure in the pbtdi parameter is not valid.
            Already_Connected = 259 //The device pointed to by pbtdi is already marked as authenticated.
        }

        #endregion

        #region PInvoke

        /// <summary>
        /// The BluetoothAuthenticateDevice function sends an authentication request to a remote Bluetooth device. Note  When developing for Windows Vista SP2 and Windows 7 the use of BluetoothAuthenticateDeviceEx is recommended
        /// </summary>
        /// <param name="hwndParent">A window to be the parent of the Authentication wizard. If set to NULL, the wizard is removed from the desktop.</param>
        /// <param name="hRadio">A valid local radio handle, or NULL. If NULL, authentication is attempted on all local radios</param>
        /// <param name="pbtdi">A structure of type BLUETOOTH_DEVICE_INFO</param>
        /// <param name="pszPasskey">A Personal Identification Number (PIN) to be used for device authentication. If set to NULL, the user interface is displayed and the user must follow the authentication process provided in the user interface</param>
        /// <param name="ulPasskeyLength">The size, in characters, of pszPasskey</param>
        /// <returns></returns>
        [DllImport("irprops.cpl", SetLastError = true)]
        public static extern uint BluetoothAuthenticateDevice(IntPtr hwndParent, IntPtr hRadio, ref BLUETOOTH_DEVICE_INFO pbtdi, [MarshalAs(UnmanagedType.LPWStr)]string pszPasskey, ulong ulPasskeyLength);

        /// <summary>
        /// The BluetoothAuthenticateDeviceEx function sends an authentication request to a remote Bluetooth device. Additionally, this function allows for out-of-band Data to be passed into the function call for the device being authenticated.
        /// </summary>
        /// <param name="hwndParentIn">[In] Optional The window to parent the authentication wizard. If NULL, the wizard will be parented off the desktop.</param>
        /// <param name="hRadioIn">[In]A valid local radio handle or NULL. If NULL, then all radios will be tried.</param>
        /// <param name="pbtdiInout">[In] [Out] A pointer to a BLUETOOTH_DEVICE_INFO structure describing the device being authenticated</param>
        /// <param name="pbtOobData">[In] Optional Pointer to device specific out-of-band Data to be provided with this API call. If NULL, then a UI is displayed to continue the authentication process. If not NULL, no UI is displayed.</param>
        /// <param name="authenticationRequirement">[In] An BLUETOOTH_AUTHENTICATION_REQUIREMENTS value that specifies the protection required for authentication</param>
        /// <returns>Returns ERROR_SUCCESS upon successful completion</returns>
        [DllImport("irprops.cpl", SetLastError = true)]
        public static extern uint BluetoothAuthenticateDeviceEx(IntPtr hwndParentIn, IntPtr hRadioIn, ref BLUETOOTH_DEVICE_INFO pbtdiInout, IntPtr pbtOobData, BLUETOOTH_AUTHENTICATION_REQUIREMENTS authenticationRequirement);

        /// <summary>
        /// The BluetoothFindFirstDevice function begins the enumeration Bluetooth devices.
        /// </summary>
        /// <param name="searchParams">[IN]Pointer to a BLUETOOTH_DEVICE_SEARCH_PARAMS structure. The dwSize member of the BLUETOOTH_DEVICE_SEARCH_PARAMS structure pointed to by pbtsp must match the size of the structure.</param>
        /// <param name="deviceInfo">[OUT]Pointer to a BLUETOOTH_DEVICE_INFO structure into which information about the first Bluetooth device found is placed</param>
        /// <returns></returns>
        [DllImport("irprops.cpl", SetLastError = true)]
        public static extern IntPtr BluetoothFindFirstDevice(ref BLUETOOTH_DEVICE_SEARCH_PARAMS searchParams, ref BLUETOOTH_DEVICE_INFO deviceInfo);

        /// <summary>
        /// Finds the first bluetooth radio present in device manager
        /// </summary>
        /// <param name="pbtfrp">Pointer to a BLUETOOTH_FIND_RADIO_PARAMS structure</param>
        /// <param name="phRadio">Pointer to where the first enumerated radio handle will be returned. When no longer needed, this handle must be closed via CloseHandle.</param>
        /// <returns>In addition to the handle indicated by phRadio, calling this function will also create a HBLUETOOTH_RADIO_FIND handle for use with the BluetoothFindNextRadio function.
        /// When this handle is no longer needed, it must be closed via the BluetoothFindRadioClose.
        /// Returns NULL upon failure. Call the GetLastError function for more information on the error. The following table describe common errors:</returns>
        [DllImport("irprops.cpl", SetLastError = true)]
        public static extern IntPtr BluetoothFindFirstRadio(ref BLUETOOTH_FIND_RADIO_PARAM pbtfrp, out IntPtr phRadio);

        /// <summary>
        /// Finds the next device in range of bluetooth
        /// </summary>
        /// <param name="hFind">Handle for the query obtained in a previous call to the BluetoothFindFirstDevice function</param>
        /// <param name="pbtdi">Pointer to a BLUETOOTH_DEVICE_INFO structure into which information about the next Bluetooth device found is placed</param>
        /// <returns>Returns TRUE when the next device is successfully found. Returns FALSE upon error</returns>
        [DllImport("Irprops.cpl", SetLastError = true)]
        public static extern bool BluetoothFindNextDevice(IntPtr hFind, ref BLUETOOTH_DEVICE_INFO pbtdi);

        /// <summary>
        /// Closes a bluetooth device
        /// </summary>
        /// <param name="hFind">Pointer to a bluetooth device</param>
        /// <returns></returns>
        [DllImport("irprops.cpl", SetLastError=true)]
        public static extern bool BluetoothFindDeviceClose(IntPtr hFind);

        /// <summary>
        /// Closes a bluetooth radio
        /// </summary>
        /// <param name="hFind">A pointer to a valid bluetooth radio</param>
        /// <returns>returns true upon successful completion.</returns>
        [DllImport("irprops.cpl", SetLastError = true)]
        public static extern bool BluetoothFindRadioClose(IntPtr hFind);

        /// <summary>
         /// The BluetoothGetRadioInfo function obtains information about a Bluetooth radio.
         /// </summary>
         /// <param name="hRadio">A handle to a local Bluetooth radio, obtained by calling the BluetoothFindFirstRadio or similar functions, or the SetupDiEnumerateDeviceInterfances function.</param>
         /// <param name="pRadioInfo">A pointer to a BLUETOOTH_RADIO_INFO structure into which information about the radio will be placed. The dwSize member of the BLUETOOTH_RADIO_INFO structure must match the size of the structure.</param>
         /// <returns>The following table lists common return values - ERROR_SUCCESS; ERROR_INVALID_PARAMETER; ERROR_REVISION_MISMATCH</returns>
        [DllImport("irprops.cpl", SetLastError = true)]
        public static extern UInt32 BluetoothGetRadioInfo(IntPtr hRadio, ref BLUETOOTH_RADIO_INFO pRadioInfo);

        /// <summary>
        /// The BluetoothRemoveDevice function removes authentication between a Bluetooth device and the computer and clears cached service information for the device.
        /// </summary>
        /// <param name="pAddress">A pointer to the Command of the Bluetooth device to be removed.</param>
        /// <returns>Returns ERROR_SUCCESS upon successful removal of the Bluetooth device. Returns ERROR_NOT_FOUND if the device was not found.</returns>
        [DllImport("irprops.cpl", SetLastError = true)]
        public static extern uint BluetoothRemoveDevice(ref  UInt64 pAddress);

         #endregion        
    }
}